在先前的例子中,我們學習如何針對我們對於數據上的需求去修改預設的後台
但是都選擇使用Django這樣具有豐富第三方庫的框架,了解人家造好什麼輪子也是很重要的事情
程式碼:https://github.com/class83108/django_project/tree/3rd_package/
今日的重點如下:
這些套件的文檔都會放在文章最下方的參考資料中
https://github.com/iamfoysal/Best-Django-Admin-interface
上面的連結中有許多套件可供選擇,都可以修改後台預設的外觀
而網站好不好看是相當主觀的事情,我這邊介紹django-jazzmin有幾個因素:
那就直接進入主題吧
poetry add django-jazzmin
# settings.py
MIDDLEWARE = [
...
"django.middleware.locale.LocaleMiddleware",
...
]
LANGUAGES = [
("en", "English"),
("zh-hant", "繁體中文"),
# 添加其他你想支持的語言
]
USE_I18N = True
# 根目錄的urls.py
from django.conf.urls.i18n import i18n_patterns
urlpatterns = [
path("i18n/", include("django.conf.urls.i18n")),
]
urlpatterns += i18n_patterns(
path("admin/", admin_site.urls),
....
# 以及其他路由
)
# settings.py
INSTALLED_APPS = [
# 控制後台主题
"jazzmin", # 一定要放在admin前面
"django.contrib.admin",
...
]
我們看一下還能做什麼調整
JAZZMIN_SETTINGS = {
# 控制網站title
"site_title": "後台管理",
# 控制sidebar的上方標題
"site_brand": "Library",
# 可以在這裡設定logo
# "site_logo": "books/img/logo.png",
# 控制登入頁面的logo 可以之後用request.user來判斷要顯示哪一個logo
"login_logo": None,
# 控制footer的版權資訊
"copyright": "Acme Library Ltd",
# 控制上方的搜尋欄可以搜尋的model,並且搭配admin的search_fields
"search_model": ["auth.User", "auth.Group", "article.ArticleV2"],
############
# Top Menu #
############
# 上方的navbar
"topmenu_links": [
# 除了控制顯示的名稱,也可以控制連結的url,並且可以設定權限
{"name": "Home", "url": "admin:index", "permissions": ["auth.view_user"]},
# 可以設定新開視窗
{
"name": "Support",
"url": "https://github.com/farridav/django-jazzmin/issues",
"new_window": True,
},
# 可以設定要去哪個model的頁面 會檢查是否有model的權限
{"model": "auth.User"},
# 可以設定要去哪個app的頁面 會檢查是否有app的權限
{"app": "article"},
],
#############
# User Menu #
#############
# 控制上方user的menu 還能有什麼額外的連結
"usermenu_links": [
{
"name": "Support",
"url": "https://github.com/farridav/django-jazzmin/issues",
"new_window": True,
},
{"model": "auth.user"},
],
#############
# Side Menu #
#############
# 可以添加自定義的連結
"custom_links": {
"article": [
{
"name": "Make Messages",
"url": "make_messages",
"icon": "fas fa-comments",
"permissions": ["auth.view_user"],
}
]
},
#################
# Related Modal #
#################
# 控制是否顯示related modal還是poup window
"related_modal_active": False,
#############
# UI Tweaks #
#############
# 可以添加自定義的css和js
"custom_css": None,
"custom_js": None,
# 控制是否顯示UI建構器
"show_ui_builder": True,
# 可以控制是否顯示語言選擇器
"language_chooser": True,
}
相比之前我們需要去寫許多程式碼來做一些客製化的需求,使用這樣的套件是不是方便許多
有關markdown編輯器,也有不同的選擇,例如
依照個人習慣選擇,對我個人而言,需要能很好的控制上傳圖片功能,並且能夠辨認table等的markdown格式(有的還真的無法辨認),使用django-mdeditor對於上述兩點需求都能做到
poetry add django-mdeditor
# settings.py
INSTALLED_APPS = [
...
'mdeditor',
]
# 如果是Django版本大於等於3
X_FRAME_OPTIONS = 'SAMEORIGIN'
# 這個我們之前就配置過了 不過要在根目錄下建立uploads資料夾
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
MEDIA_URL = '/media/'
# urls.py
urlpatterns = [
path("mdeditor/", include("mdeditor.urls")),
]
# 需要注意要放在他前面,不然上傳圖片會有問題
urlpatterns += [
path("i18n/", include("django.conf.urls.i18n")),
]
# article.models.py
from mdeditor.fields import MDTextField
class ArticleV2(models.Model):
...
content = MDTextField(verbose_name="內容")
# bash
python3 manage.py makemigrations
python3 manage.py migrate
另外點擊圖片的彈窗會跑版,所以可以針對這個元素去調整css,至於該怎麼做,前面介紹很多了這邊就不贅述
還有一點需要注意,在Django in 2024: 解鎖Django form的潛力中配置了form表單的markdown顯示等特殊功能。
如果要再自行調整會比較需要注意,因此當我自己有特殊邏輯需求時,我自己覺得搭配簡單的JS庫可能更容易,可以專注使用django form以及admin處理我的邏輯,但是如果是很單純需要快速開發,我就會選擇該套件
Django使用ORM語法雖然讓許多查詢變得更直觀,但是也更應該注意是否寫了效能不好的寫法,甚至呼叫太多次資料庫造成多餘的負荷
poetry add django-debug-toolbar==4.2.0
# settings.py
INSTALLED_APPS = [
...
"debug_toolbar",
...
]
MIDDLEWARE = [
# 放在第一個
"debug_toolbar.middleware.DebugToolbarMiddleware",
...
]
INTERNAL_IPS = [
"127.0.0.1",
]
#Debug Toolbar默認只在來自INTERNAL_IPS中列出的IP位置的請求中顯示
# urls.py
if settings.DEBUG:
import debug_toolbar
urlpatterns += [
path("__debug__/", include(debug_toolbar.urls)),
]
我們就能在頁面上看到啦
我們進到文章修改頁後點擊SQL的部分,可以看到在計算文章數量上重複了兩次
可以看到造成兩次查詢的原因分別為以下方法
full_result_count = self.root_queryset.count()
:用來顯示總筆數result_count = paginator.count
:這是為了獲取當前頁的記錄數(result_count)。Django的分頁器使用這個數字來計算當前頁面應該顯示的記錄數量我們可以透過這些資訊,來了解到是不是有需要設定相關的快取或是資料庫的索引進行優化,端看是寫入頻率遠小於讀取頻率的狀況
我嘗試了像django-admin-charts
等根據Model來生成資料的套件,發現可能會有幾個問題
後來還是覺得回歸最單純的方法,讓Django做它擅長的事情:透過ORM提取資料,至於頁面的部分?交給JS來處理
我之前也有寫過一篇使用ECharts跟Django整合的文章
但是那邊是單純的只是用View返回JSON,這裡則是在後台進行整合
因為我們的資料目前筆數真的不多,所以請AI直接根據我們的資料來生成對應的資料
我這裡ArticleV2的content欄位已經改為原本的JSONField
並且遷移過了需要注意
# 修改欄位
content = JSONField(default=dict, verbose_name="內容")
# content = MDTextField(verbose_name="內容")
腳本的連結如下,直接執行就可以了
https://github.com/class83108/django_project/blob/3rd_package/django_project/add_articles.py
資料都準備好了,那先說明我們的需求
# custom_admin_page.html
{% extends "admin/base_site.html" %}
{% block extrahead %}
{{ block.super }}
{% endblock extrahead %}
{% block content %}
<div>
<canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
const ctx = document.getElementById('myChart');
new Chart(ctx, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
</script>
{% endblock %}
從上方的資料來看,我們只需要拿到label
(x軸標籤)與其對應的資料datasets
就能完成我們的需求
因為可能不只一個頁面需要圖表,所以在跟目錄下建立utility資料夾,並設置:
# create_charts.py
from article.models import Tag
from django.db.models import Count
import json
def get_tags_count() -> dict:
tags_count = Tag.objects.annotate(count=Count("articlev2")).values_list(
"name", "count"
)
# 做成JSON,如果用AJAX調用時也更方便
return json.dumps(
{
"labels": [tag[0] for tag in tags_count],
"data": [tag[1] for tag in tags_count],
}
)
# __init__.py
from .create_charts import get_tags_count
# article.views.py
from utility import get_tags_count
import json
class CustomAdminPageView(TemplateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) # 獲取原始的上下文數據
# 獲取傳遞的 AdminSite 實例
admin_site = self.admin_site or self.request.site
if admin_site:
...
# 添加額外的上下文數據
context.update(
{
...
# 新增這裡
"tag_count_result": json.loads(get_tags_count()),
}
)
return context
# custom_admin_page.html
{% extends "admin/base_site.html" %}
{% block extrahead %}
{{ block.super }}
{% endblock extrahead %}
{% block content %}
<div class="container">
<div class="row">
<div class="col">
<canvas id="myChart"></canvas>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
const ctx = document.getElementById('myChart');
new Chart(ctx, {
type: 'bar',
data: {
labels: {{ tag_count_result.labels | safe }}, # 如果是陣列就需要添加safe
datasets: [{
label: 'Tag Count',
data: {{ tag_count_result.data | safe }},
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
</script>
{% endblock %}
就能看到成果了!
今天我們透過使用不同的套件來修改後台
今天的範例都沒有做比較深入的應用,主要的目的是要讓大家知道有這些工具可以做應用
再根據個人需求去延伸每一部分的深度與廣度,不知道有沒有藉此激發一些想在後台實施相關功能的想法
明天我們會探討在後台中,Django是怎麼利用User model來進行用戶管理